var canvas = document.getElementById('screen');
         var ctx = canvas.getContext('2d');
         
         var img = new Image();
         img.src = '../public/img/pic10.jpg';
         img.onload = loadImg;
         
         document.getElementById('control_reset').onclick = imgReset;
         document.getElementById('control_gray').onclick = imgGray;
         document.getElementById('control_otsu').onclick = imgOtsu;
         document.getElementById('control_histo').onclick = imgHisto;
         
         /**
          * Loads an image into the canvas context
          */
         function loadImg()
         {
            canvas.width = 800;
            canvas.height = 500;
            ctx.drawImage(img, 0, 0, img.width, img.height);
            
            logById('info_imgloaded', img.src);
            logById('info_imgwidth', img.width);
            logById('info_imgheight', img.height);
         }
         
         
         /**
          * Inserts a message inside a DOM element given its id
          */
         function logById(id, msg)
         {
            document.getElementById(id).innerText = msg;
         }
         
         
         /**
          * Reloads the default image assigned to be displayed in the global canvas context
          */
         function imgReset()
         {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            loadImg();
         }
         
         
         /*
          * Grayscales the pixel data in the global canvas context
          */
         function imgGray()
         {
            var pxData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            var len = pxData.data.length;
            
            for(var i = 0; i < len; i+= 4)
            {
               var gray = pxData.data[i] * 0.21 + pxData.data[i + 1] * 0.71 + pxData.data[i + 2] * 0.07;
               
               pxData.data[i] = gray;
               pxData.data[i + 1] = gray;
               pxData.data[i + 2] = gray;
            }
            
            ctx.putImageData(pxData, 0, 0);
         }
         
         
         /**
          * Sum the numbers in an array. Return the parameter if it's not an array
          */
         function getSum(arr)
         {
            if(! arr instanceof Array)
               return arr;
            
            var sum = 0;
            var len = arr.length;
            
            for(var i = 0; i < len; i++)
               sum += arr[i];
            
            return sum;
         }
         
         
         /**
          * Calculate mean value of an array
          */
         function getMean(arr, frequencyStart)
         {
            if(arguments.length == 1)
               frequencyStart = 0;
            
            var totalSum = 0;
            var sumOfFrequencies = 0;
            
            var len = arr.length;
            
            for(var i = 0; i < len; i++)
            {
               totalSum += arr[i];
               sumOfFrequencies += frequencyStart * arr[i];
               
               frequencyStart++;
            }
            
            if(totalSum < 1)
               return 0;
            
            return sumOfFrequencies / totalSum;
         }
         
         
         
         /**
          * Calculate variance of an array
          */
         function getVariance(arr, frequencyStart)
         {
            if(arguments.length == 1)
               frequencyStart = 0;
            
            var mean = getMean(arr, frequencyStart);
            
            var totalSum = 0;
            var sumOfFrequencies = 0;
            
            var len = arr.length;
            
            for(var i = 0; i < len; i++)
            {
               totalSum += arr[i];
               
               sumOfFrequencies += (frequencyStart - mean) * (frequencyStart - mean) * arr[i];
               
               frequencyStart++;
            }
            
            if(totalSum < 1)
               return 0;
            
            return sumOfFrequencies / totalSum;
         }
         
         
         function getThreshold(arr)
         {
            var varianceIndex = 0;
            var variance = arr[varianceIndex];
            var len = arr.length;
            
            for(var i = 0; i < len; i++)
            {
               if(isNaN(arr[i]))
                  arr[i] = 9999999;
               
               if(arr[i] < variance)
               {
                  variance = arr[i];
                  varianceIndex = i;
               }
            }
            
            return varianceIndex;
         }
         
         /**
          * Uses Otsu's thresholding method to create a binary image out of the pixel data in the global canvas context
          */
         function imgOtsu()
         {
            var pxData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            var len = pxData.data.length;
            
            /*
            var min = 255;
            var max = 0;
            
            for(var i = 0; i < len; i+= 4)
            {
               if(pxData.data[i] > max)
                  max = pxData.data[i];
               
               if(pxData.data[i] < min)
                  min = pxData.data[i];
            }
            
            
            var avg = (min + max) / 2;
            */
           
            var totalBuckets = 10;
            var histogram = imgHistoNotNorm(totalBuckets);
            var bucket = 256 / totalBuckets;
            var total = histogram.len;
            histogram = histogram.histogram;

            var T = [];
            
            // Find threshold value
            var histogramLen = histogram.length;
            
            // Try every possible threshold value
            for(var t = 0; t < histogramLen; t++)
            {
               var otsuBack = [];
               var otsuFore = [];

               var weightBack = 0;
               var weightFore = 0;

               var meanBack = 0;
               var meanFore = 0;

               var varianceBack = 0;
               var varianceFore = 0;
            
               // Calculate the weight
               for(var i = 0; i < histogramLen; i++)
               {
                  if(histogram[i] > (t + 1) * bucket)
                     otsuFore.push(histogram[i]);
                  else
                     otsuBack.push(histogram[i]);
               }
               
               console.log('Loop = ' + t);
               console.log('Histogram = ' + histogram);
               console.log('Histogram length = ' + histogramLen);
               console.log('total = ' + total);
               
               console.log('Otsu Back = ' + otsuBack);
               console.log('Otsu Fore = ' + otsuFore);
               
               weightBack = getSum(otsuBack) / total;
               weightFore = getSum(otsuFore) / total;
               console.log('Weight = ' + weightBack + ', ' + weightFore);
               
               meanBack = getMean(otsuBack, 0);
               meanFore = getMean(otsuFore, otsuBack.length);
               console.log('Mean = ' + meanBack + ', ' + meanFore);
               
               varianceBack = getVariance(otsuBack, 0);
               varianceFore = getVariance(otsuFore, otsuBack.length);
               console.log('Variance = ' + varianceBack + ', ' + varianceFore);
               
               T.push(weightBack * varianceBack + weightFore * varianceFore);
               console.log('T[' + t + '] = ' + T[t]);
               console.log('--------------------------------------');
            }
            
            T = getThreshold(T) * (256 / histogramLen);
            logById('info_log', 'T = ' + T);            

            for(var i = 0; i < len; i+= 4)
            {
               if(pxData.data[i] > T)
               {
                  pxData.data[i] = 255;
                  pxData.data[i + 1] = 255;
                  pxData.data[i + 2] = 255;
               }
               else
               {
                  pxData.data[i] = 0;
                  pxData.data[i + 1] = 0;
                  pxData.data[i + 2] = 0;
               }
            }
            
            ctx.putImageData(pxData, 0, 0);
            
         }
         
         
         function imgHisto()
         {
            var pxData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            var len = pxData.data.length;
            
            var buckets = 23;
            var totalItems = 0;
            var histogram = [];
            
            for(var i = 0; i < buckets; i++)
               histogram[i] = 0;
            
            for(var i = 0; i < len; i += 4)
            {
               var bucket = parseInt(pxData.data[i] / buckets)
               histogram[bucket] += 1;
               totalItems++;
            }
            
            for(var i = 0; i < buckets; i++)
               histogram[i] /= totalItems;
            
            logById('info_log', histogram);
            
            return histogram;
            
         }
         
         function imgHistoNotNorm(pBuckets)
         {
            var pxData = ctx.getImageData(0, 0, canvas.width, canvas.height);
            var len = pxData.data.length;
            
            var buckets = pBuckets;
            var bucket = 256 / buckets;
            var totalItems = 0;
            var histogram = [];
            
            for(var i = 0; i < buckets; i++)
               histogram[i] = 0;
            
            var bucketIndexes = []
            
            for(var i = 0; i < len; i += 4)
            {
               var index = parseInt(pxData.data[i] / bucket);
               histogram[index] += 1;
               totalItems++;
               
               bucketIndexes.push(index);
            }
            
            return {histogram: histogram, len: totalItems};
         }
         
         
         
         /**
          * Gets a part of the grid (from 1 to 9) and shades it red
          */
         $('.control_grid_btn').live('click', function(){
            
            var grid = $(this).attr('id').substr('control_grid'.length);
            
            var col = parseInt(img.width / 3);
            var row = parseInt(img.height / 3);
            
            var start_x = parseInt((grid - 1) % 3) * col;
            var start_y = parseInt((grid - 1) / 3) * row;
            
            var end_x = img.width / 3;
            var end_y = img.height / 3;
            
            
            // Special case last col to get last col on right
            if(start_x / col == 2)
               end_x += 4;
            
            // Special case last row to get last row on bottom
            if(start_y / row == 2)
               end_y += 4;
            
            
            //
            // For modularized functionality, return this pxData array:
            // ctx.getImageData(start_x, start_y, end_x, end_y);
            //
            var pxData = ctx.getImageData(start_x, start_y, end_x, end_y);
            var len = pxData.data.length;
            
            for(var i = 0; i < len; i += 4)
            {
               pxData.data[i + 1] = pxData.data[i] / 2;
               pxData.data[i + 2] = pxData.data[i] / 2;
            }
            
            ctx.putImageData(pxData, start_x, start_y);
            
         });
         
         
         $('.grid_img').live('click', function(){
            img.src = $(this).attr('src');
            
         });
         
         (function loadGrid()
         {
            var img;
            for(var i = 10; i < 35; i++)
            {
               img = '<img src="../public/img/pic' + i + '.jpg" id="grid_img_' + i + '" class="grid_img"/>';
               document.getElementById('img_grid').innerHTML += img;
            }
            
         })();